package com.ltg.framework.mybatis.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ltg.framework.core.util.ClazzUtils;
import com.ltg.framework.core.util.JsonUtils;
import com.ltg.framework.mybatis.entity.BaseEntity;
import com.ltg.framework.mybatis.exception.FailedToCreateErrorException;
import com.ltg.framework.mybatis.exception.FailedToNotFoundErrorException;
import com.ltg.framework.mybatis.exception.FailedToOperationErrorException;
import com.ltg.framework.mybatis.exception.FailedToUpdateErrorException;
import com.ltg.framework.mybatis.help.PageResult;
import com.ltg.framework.mybatis.help.QMap;
import com.ltg.framework.mybatis.mapper.PlusMapper;
import com.ltg.framework.mybatis.service.IPlusService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ReflectionUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * nekoimi  2021/6/13 上午12:03
 */
@Slf4j
public class PlusServiceImpl<M extends PlusMapper<E>, E extends BaseEntity> implements IPlusService<E> {

    @Autowired
    private M mapper;
    @Autowired
    private IdentifierGenerator idGenerator;


    protected LambdaQueryWrapper<E> applyQueryConsumer(Consumer<LambdaQueryWrapper<E>> consumer) {
        LambdaQueryWrapper<E> query = newLambdaQuery();
        consumer.accept(query);
        return query;
    }

    protected LambdaUpdateWrapper<E> applyUpdateConsumer(Consumer<LambdaUpdateWrapper<E>> consumer) {
        LambdaUpdateWrapper<E> query = newLambdaUpdate();
        consumer.accept(query);
        return query;
    }

    protected LambdaQueryWrapper<E> applyQueryMapConsumer(Consumer<QMap<SFunction<E, Object>, Object>> consumer) {
        LambdaQueryWrapper<E> query = newLambdaQuery();
        QMap<SFunction<E, Object>, Object> queryMap = newQMap();
        consumer.accept(queryMap);
        queryMap.forEach(query::eq);
        return query;
    }

    protected LambdaUpdateWrapper<E> applyUpdateMapConsumer(Consumer<QMap<SFunction<E, Object>, Object>> consumer) {
        LambdaUpdateWrapper<E> update = newLambdaUpdate();
        QMap<SFunction<E, Object>, Object> updateMap = newQMap();
        consumer.accept(updateMap);
        updateMap.forEach(update::set);
        return update;
    }

    protected E checkGetFail(E e) {
        if (e == null) {
            throw new FailedToNotFoundErrorException("entity is not exists");
        }
        return e;
    }

    protected Boolean checkExists(E e) {
        return e != null;
    }

    protected Boolean rowToBoolean(Integer rows) {
        return rows != null && rows > 0;
    }

    protected E copyMapToEntity(Map<String, Object> map) {
        E e = ClazzUtils.newInstance(currentModelClass());
        if (e == null) {
            throw new FailedToOperationErrorException("not fin entity");
        }

        currentTableFieldList().stream().filter(info -> map.containsKey(info.getProperty())).forEach(info -> {
            Object propertyValue = map.get(info.getProperty());
            Class<?> propertyType = info.getPropertyType();
            if (propertyValue instanceof Map<?, ?> || propertyValue instanceof Collection<?>) {
                String json = JsonUtils.write(propertyValue);
                propertyValue = JsonUtils.read(json, propertyType);
            }
            if (ClazzUtils.instanceOf(propertyType, Map.class) || ClazzUtils.instanceOf(propertyType, Collection.class)) {
                if (propertyValue instanceof CharSequence) {
                    String json = propertyValue.toString();
                    propertyValue = JsonUtils.read(json, propertyType);
                }
            }
            Field field = ReflectionKit.setAccessible(info.getField());
            ReflectionUtils.setField(field, e, propertyValue);
        });

        Stream.of(currentPrimaryKeyProperty()).map(Objects::toString).filter(map::containsKey).forEach(s -> {
            Field field = currentPrimaryKeyField();
            if (field == null) {
                throw new FailedToOperationErrorException("Primary key field not found!");
            }
            ReflectionUtils.setField(ReflectionKit.setAccessible(field), e, map.get(s));
        });

        return e;
    }

    @Override
    public String primaryKeyId() {
        return idGenerator.nextUUID(null);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Class<E> currentModelClass() {
        return (Class<E>) ReflectionKit.getSuperClassGenericType(this.getClass(), PlusServiceImpl.class, 1);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Class<M> currentMapperClass() {
        return (Class<M>) ReflectionKit.getSuperClassGenericType(this.getClass(), PlusServiceImpl.class, 0);
    }

    @Override
    public M currentMapper() {
        return mapper;
    }

    @Override
    public TableInfo currentTableInfo() {
        return TableInfoHelper.getTableInfo(currentModelClass());
    }

    @Override
    public Serializable currentPrimaryKeyProperty() {
        return currentTableInfo().getKeyProperty();
    }

    @Override
    public Field currentPrimaryKeyField() {
        return ReflectionKit.getFieldList(currentModelClass()).stream().filter(f -> Objects.equals(currentPrimaryKeyProperty(), f.getName())).findFirst().orElse(null);
    }

    /**
     * <p>
     * 返回不包括主键的其他字段集合, 参考: {@link TableInfoHelper#initTableFields(Class, com.baomidou.mybatisplus.core.config.GlobalConfig, TableInfo, List)}
     * </p>
     *
     * @return
     */
    @Override
    public List<TableFieldInfo> currentTableFieldList() {
        return currentTableInfo().getFieldList();
    }

    @Override
    public QMap<SFunction<E, Object>, Object> newQMap() {
        return new QMap<>(new HashMap<>());
    }

    @Override
    public QueryWrapper<E> newQuery() {
        return new QueryWrapper<E>();
    }

    @Override
    public LambdaQueryWrapper<E> newLambdaQuery() {
        return Wrappers.lambdaQuery(currentModelClass());
    }

    @Override
    public LambdaUpdateWrapper<E> newLambdaUpdate() {
        return Wrappers.lambdaUpdate(currentModelClass());
    }

    @Transactional(readOnly = true)
    @Override
    public E getById(Serializable id) {
        return currentMapper().selectById(id);
    }

    @Transactional(readOnly = true)
    @Override
    public E getByQuery(Consumer<LambdaQueryWrapper<E>> consumer) {
        return currentMapper().selectOne(applyQueryConsumer(consumer));
    }

    @Transactional(readOnly = true)
    @Override
    public E getByMap(Consumer<QMap<SFunction<E, Object>, Object>> consumer) {
        return currentMapper().selectOne(applyQueryMapConsumer(consumer));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1) {
        return getByMap(map -> map.put(k1, v1));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2) {
        return getByMap(map -> map.put(k1, v1).put(k2, v2));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3) {
        return getByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4) {
        return getByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5) {
        return getByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6) {
        return getByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7) {
        return getByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8) {
        return getByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7).put(k8, v8));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8, SFunction<E, Object> k9, Object v9) {
        return getByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7).put(k8, v8).put(k9, v9));
    }

    @Override
    public E getOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8, SFunction<E, Object> k9, Object v9, SFunction<E, Object> k10, Object v10) {
        return getByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7).put(k8, v8).put(k9, v9).put(k10, v10));
    }

    @Override
    public E getByIdOrFail(Serializable id) {
        return checkGetFail(getById(id));
    }

    @Override
    public E getByQueryOrFail(Consumer<LambdaQueryWrapper<E>> consumer) {
        return checkGetFail(getByQuery(consumer));
    }

    @Override
    public E getByMapOrFail(Consumer<QMap<SFunction<E, Object>, Object>> consumer) {
        return checkGetFail(getByMap(consumer));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1) {
        return checkGetFail(getOf(k1, v1));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2) {
        return checkGetFail(getOf(k1, v1, k2, v2));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3) {
        return checkGetFail(getOf(k1, v1, k2, v2, k3, v3));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4) {
        return checkGetFail(getOf(k1, v1, k2, v2, k3, v3, k4, v4));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5) {
        return checkGetFail(getOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6) {
        return checkGetFail(getOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7) {
        return checkGetFail(getOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8) {
        return checkGetFail(getOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8, SFunction<E, Object> k9, Object v9) {
        return checkGetFail(getOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9));
    }

    @Override
    public E getOfOrFail(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8, SFunction<E, Object> k9, Object v9, SFunction<E, Object> k10, Object v10) {
        return checkGetFail(getOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10));
    }

    @Override
    public Boolean exists(Serializable id) {
        return checkExists(getById(id));
    }

    @Override
    public Boolean existsOf(SFunction<E, Object> k1, Object v1) {
        return existsByMap(map -> map.put(k1, v1));
    }

    @Override
    public Boolean existsByQuery(Consumer<LambdaQueryWrapper<E>> consumer) {
        return checkExists(getByQuery(consumer));
    }

    @Override
    public Boolean existsByMap(Consumer<QMap<SFunction<E, Object>, Object>> consumer) {
        return checkExists(getByMap(consumer));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Serializable save(E e) {
        Serializable keyValue = e.getId();
        if (keyValue == null || keyValue.toString().length() <= 0) {
            Field keyField = currentPrimaryKeyField();
            if (keyField == null) {
                throw new FailedToOperationErrorException("Primary key field not found!");
            }
            TableId tableId = keyField.getDeclaredAnnotation(TableId.class);
            if (tableId != null && (tableId.type() == IdType.ASSIGN_ID || tableId.type() == IdType.ASSIGN_UUID)) {
                keyValue = primaryKeyId();
                ReflectionUtils.setField(ReflectionKit.setAccessible(keyField), e, keyValue);
            }
        }
        Boolean bool = rowToBoolean(currentMapper().insert(e));
        if (!bool) {
            throw new FailedToCreateErrorException("");
        }
        return keyValue;
    }

    @Override
    public Serializable saveMap(Map<String, Object> map) {
        return save(copyMapToEntity(map));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveBatch(List<E> entityList) {
        entityList.forEach(this::save);
    }

    /**
     * <p>插入或者更新</p>
     * <p>
     * FIXME：这里最好换成分布式锁!!!
     *
     * @param e 操作对象
     * @return
     */
    @Override
    public synchronized Serializable saveOrUpdate(E e) {
        Serializable keyValue = e.getId();
        if (keyValue == null || keyValue.toString().length() <= 0) {
            return save(e);
        }
        if (exists(keyValue)) {
            if (!update(e)) {
                throw new FailedToUpdateErrorException("Entity is not extends");
            }
            return keyValue;
        } else {
            return save(e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean update(E entity) {
        return rowToBoolean(currentMapper().updateById(entity));
    }

    @Override
    public void updateBatch(String ids, Map<String, Object> map) {
        updateBatch(Arrays.asList(ids.split("[,]")), map);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateBatch(List<? extends Serializable> idList, Map<String, Object> map) {
        idList.forEach(id -> updateByIdOfMap(id, map));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateByQuery(E entity, Consumer<LambdaUpdateWrapper<E>> consumer) {
        return rowToBoolean(currentMapper().update(entity, applyUpdateConsumer(consumer)));
    }

    @Override
    public Boolean updateById(Serializable id, E e) {
        if (!exists(id)) {
            throw new FailedToNotFoundErrorException("Primary key is not exist");
        }
        Field keyField = currentPrimaryKeyField();
        if (keyField == null) {
            throw new FailedToNotFoundErrorException("Primary key field not found!");
        }
        ReflectionUtils.setField(ReflectionKit.setAccessible(keyField), e, id);
        return update(e);
    }

    @Override
    public Boolean updateByIdOfMap(Serializable id, Map<String, Object> map) {
        map.put(currentTableInfo().getKeyProperty(), id);
        return update(copyMapToEntity(map));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateById(Serializable id, Consumer<LambdaUpdateWrapper<E>> consumer) {
        E e = getByIdOrFail(id);
        return rowToBoolean(currentMapper().update(e, applyUpdateConsumer(consumer)));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateByIdOfMap(Serializable id, Consumer<QMap<SFunction<E, Object>, Object>> consumer) {
        E e = getByIdOrFail(id);
        return rowToBoolean(currentMapper().update(e, applyUpdateMapConsumer(consumer)));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1) {
        return updateByIdOfMap(id, m -> m.put(k1, v1));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2) {
        return updateByIdOfMap(id, m -> m.put(k1, v1).put(k2, v2));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3) {
        return updateByIdOfMap(id, m -> m.put(k1, v1).put(k2, v2).put(k3, v3));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4) {
        return updateByIdOfMap(id, m -> m.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5) {
        return updateByIdOfMap(id, m -> m.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6) {
        return updateByIdOfMap(id, m -> m.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7) {
        return updateByIdOfMap(id, m -> m.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8) {
        return updateByIdOfMap(id, m -> m.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7).put(k8, v8));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8, SFunction<E, Object> k9, Object v9) {
        return updateByIdOfMap(id, m -> m.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7).put(k8, v8).put(k9, v9));
    }

    @Override
    public Boolean updateOf(Serializable id, SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8, SFunction<E, Object> k9, Object v9, SFunction<E, Object> k10, Object v10) {
        return updateByIdOfMap(id, m -> m.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7).put(k8, v8).put(k9, v9).put(k10, v10));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeById(Serializable id) {
        currentMapper().deleteById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeByQuery(Consumer<LambdaQueryWrapper<E>> consumer) {
        currentMapper().delete(applyQueryConsumer(consumer));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeBatch(String ids) {
        removeBatch(Arrays.asList(ids.split("[,]")));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeBatch(List<? extends Serializable> idList) {
        currentMapper().deleteBatchIds(idList);
    }

    @Transactional(readOnly = true)
    @Override
    public long countAll() {
        return currentMapper().selectCount(newLambdaQuery());
    }

    @Transactional(readOnly = true)
    @Override
    public long countByQuery(Consumer<LambdaQueryWrapper<E>> consumer) {
        return currentMapper().selectCount(applyQueryConsumer(consumer));
    }

    @Transactional(readOnly = true)
    @Override
    public long countByMap(Consumer<QMap<SFunction<E, Object>, Object>> consumer) {
        return currentMapper().selectCount(applyQueryMapConsumer(consumer));
    }

    @Transactional(readOnly = true)
    @Override
    public List<E> findAll() {
        return currentMapper().selectList(newLambdaQuery());
    }

    @Transactional(readOnly = true)
    @Override
    public List<E> findByIds(List<? extends Serializable> ids) {
        return currentMapper().selectBatchIds(ids);
    }

    @Transactional(readOnly = true)
    @Override
    public List<E> findByQuery(Consumer<LambdaQueryWrapper<E>> consumer) {
        return currentMapper().selectList(applyQueryConsumer(consumer));
    }

    @Override
    public List<E> findByMap(Consumer<QMap<SFunction<E, Object>, Object>> consumer) {
        return currentMapper().selectList(applyQueryMapConsumer(consumer));
    }

    @Override
    @SafeVarargs
    public final List<E> findAllSelectColumn(SFunction<E, Object>... columns) {
        return currentMapper().selectList(newLambdaQuery().select(columns));
    }

    @SafeVarargs
    @Override
    public final List<E> findByQuerySelectColumn(Consumer<LambdaQueryWrapper<E>> consumer, SFunction<E, Object>... columns) {
        return currentMapper().selectList(applyQueryConsumer(consumer).select(columns));
    }

    @SafeVarargs
    @Override
    public final List<E> findByMapSelectColumn(Consumer<QMap<SFunction<E, Object>, Object>> consumer, SFunction<E, Object>... columns) {
        return currentMapper().selectList(applyQueryMapConsumer(consumer).select(columns));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1) {
        return findByMap(map -> map.put(k1, v1));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2) {
        return findByMap(map -> map.put(k1, v1).put(k2, v2));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3) {
        return findByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4) {
        return findByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5) {
        return findByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6) {
        return findByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7) {
        return findByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8) {
        return findByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7).put(k8, v8));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8, SFunction<E, Object> k9, Object v9) {
        return findByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7).put(k8, v8).put(k9, v9));
    }

    @Override
    public List<E> findOf(SFunction<E, Object> k1, Object v1, SFunction<E, Object> k2, Object v2, SFunction<E, Object> k3, Object v3, SFunction<E, Object> k4, Object v4, SFunction<E, Object> k5, Object v5, SFunction<E, Object> k6, Object v6, SFunction<E, Object> k7, Object v7, SFunction<E, Object> k8, Object v8, SFunction<E, Object> k9, Object v9, SFunction<E, Object> k10, Object v10) {
        return findByMap(map -> map.put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).put(k6, v6).put(k7, v7).put(k8, v8).put(k9, v9).put(k10, v10));
    }

    @Transactional(readOnly = true)
    @Override
    public PageResult<E> page(IPage<E> page) {
        return new PageResult<>(currentMapper().selectPage(page, newLambdaQuery().orderByDesc(BaseEntity::getCreateTime)));
    }

    @SafeVarargs
    @Override
    public final PageResult<E> page(IPage<E> page, SFunction<E, Object>... columns) {
        return page(page, eqw -> eqw.select(columns));
    }

    @Transactional(readOnly = true)
    @Override
    public PageResult<E> page(IPage<E> page, Consumer<LambdaQueryWrapper<E>> consumer) {
        return new PageResult<>(currentMapper().selectPage(page, applyQueryConsumer(consumer)));
    }


    /**
     * ===============================================================================
     * DynamicCurdService
     * ===============================================================================
     */

    @Override
    public int insert(Map<String, Object> map) {
        saveMap(map);
        return 1;
    }

    @Override
    public int deleteById(Serializable id) {
        removeById(id);
        return 1;
    }

    @Override
    public int deleteByMap(Map<String, Object> columnMap) {
        return 0;
    }

    @Override
    public int deleteBatchIds(Collection<? extends Serializable> idList) {
        removeBatch(new ArrayList<>(idList));
        return 1;
    }

    @Override
    public int updateById(Serializable id, Map<String, Object> columnMap) {
        updateByIdOfMap(id, columnMap);
        return 1;
    }

    @Override
    public Map<String, Object> selectById(Serializable id) {
        E e = getByIdOrFail(id);
        return Convert.convert(new TypeReference<Map<String, Object>>() {
        }, e);
    }

    @Override
    public List<Map<String, Object>> selectBatchIds(Collection<? extends Serializable> idList) {
        return findByIds(new ArrayList<>(idList)).stream().map(e -> Convert.convert(new TypeReference<Map<String, Object>>() {
        }, e)).collect(Collectors.toList());
    }

    @Override
    public List<Map<String, Object>> selectByMap(Map<String, Object> columnMap) {
        return new ArrayList<>();
    }

    @Override
    public Integer selectCount(Map<String, Object> columnMap) {
        return 0;
    }

    @Override
    public List<Map<String, Object>> selectList(Map<String, Object> columnMap) {
        return new ArrayList<>();
    }

    @Override
    public IPage<Map<String, Object>> selectListPage(IPage<Map<String, Object>> page, Map<String, Object> columnMap) {
        return new Page<>();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateAndSave(List<E> entities) {
        for (E entity : entities) {
            Long id = entity.getId();
            Boolean exists = this.exists(id);
            if (Boolean.TRUE.equals(exists)) {
                this.update(entity);
            } else {
                this.save(entity);
            }
        }
        return 0;
    }
}
